package com.polaris.live.ui.live.fragment

import android.app.Activity
import android.os.Bundle
import android.text.TextUtils
import android.view.View
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.viewModelScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.blankj.utilcode.util.AppUtils
import com.blankj.utilcode.util.ConvertUtils
import com.blankj.utilcode.util.GsonUtils
import com.blankj.utilcode.util.ScreenUtils
import com.blankj.utilcode.util.StringUtils
import com.blankj.utilcode.util.Utils
import com.bumptech.glide.Glide
import com.gyf.immersionbar.ImmersionBar
import com.polaris.live.R
import com.polaris.live.adapter.CallGiftAdapter
import com.polaris.live.cache.CommonCache
import com.polaris.live.common.cacha.CacheUtil
import com.polaris.live.common.cacha.UserManager
import com.polaris.live.common.constant.AppConst
import com.polaris.live.common.ext.convertArabicDigitsToNormal
import com.polaris.live.common.ext.setOnSingleClickListener
import com.polaris.live.common.manager.CoroutineScopeManager
import com.polaris.live.common.network.EncryptHelper
import com.polaris.live.common.network.parseState
import com.polaris.live.common.recyclerview.CommonItemDecoration
import com.polaris.live.common.util.DebounceHelper
import com.polaris.live.common.util.NavigationBarUtils
import com.polaris.live.common.util.ToastGravity
import com.polaris.live.common.util.ViewUtils
import com.polaris.live.common.util.ifDestroy
import com.polaris.live.constant.LiveConst
import com.polaris.live.constant.UserConst
import com.polaris.live.databinding.FragmentCallLiveVideoBinding
import com.polaris.live.dialog.CallHangUpDialog
import com.polaris.live.dialog_fragment.GiftDialogFragment
import com.polaris.live.im.manager.ImCallManager
import com.polaris.live.im.sfs.CALL_REFUSE_INTERPRETATION
import com.polaris.live.im.sfs.COMMAND_CALL_ANSWER
import com.polaris.live.im.sfs.COMMAND_CALL_END
import com.polaris.live.im.sfs.COMMAND_CALL_NO_ANSWER
import com.polaris.live.im.sfs.COMMAND_CALL_REFUSE
import com.polaris.live.im.sfs.LIVE_GIFT_LIST
import com.polaris.live.im.sfs.LIVE_MASKING_MESSAGE
import com.polaris.live.im.sfs.LIVE_OCCLUSION_MESSAGE
import com.polaris.live.im.sfs.LIVE_RECHARGE_PAY
import com.polaris.live.im.sfs.LIVE_SEND_GIFT
import com.polaris.live.im.sfs.LIVE_TRANSLATION_MESSAGE
import com.polaris.live.im.sfs.LIVE_WARN_MESSAGE
import com.polaris.live.im.sfs.REQUEST_GIFT_POPUP_MESSAGE
import com.polaris.live.im.sfs.bean.live.CallSignalingMessage
import com.polaris.live.im.sfs.bean.live.ext.UserBasicVo
import com.polaris.live.im.sfs.bean.live.payload.CallLaunchRechargePayloadBean
import com.polaris.live.im.sfs.bean.live.payload.CallObstructPayloadBean
import com.polaris.live.im.sfs.bean.live.payload.GiftListPayloadBean
import com.polaris.live.im.sfs.bean.live.payload.InviteGiftPayloadBean
import com.polaris.live.im.sfs.bean.live.payload.InviteGiftPopupPayloadDto
import com.polaris.live.im.sfs.bean.live.payload.SimultaneousStartPayloadBean
import com.polaris.live.manager.GooglePayManager
import com.polaris.live.manager.LiveStateManager
import com.polaris.live.popup.GlobalPopupManager
import com.polaris.live.popup.GlobalPopupManager.showUserProfilePopup
import com.polaris.live.popup.PublicTipsPopup
import com.polaris.live.popup.RequestGiftPopup
import com.polaris.live.popup.SetTranslationPopup
import com.polaris.live.popup.WeeklyStarPopup
import com.polaris.live.resp.back_resp.CallStartResp
import com.polaris.live.resp.back_resp.CallVo
import com.polaris.live.resp.back_resp.GiftBean
import com.polaris.live.resp.back_resp.InfoOtherResp
import com.polaris.live.resp.back_resp.RecognizeModel
import com.polaris.live.resp.back_resp.toUserBasicVo
import com.polaris.live.resp.event.BackgroundEvent
import com.polaris.live.resp.event.LiveRechargeEvent
import com.polaris.live.resp.go_resp.SendGiftBean
import com.polaris.live.translation.R.string
import com.polaris.live.ui.live.fragment.base.GestureFragment
import com.polaris.live.ui.live.proxy.LiveMoreProxy
import com.polaris.live.ui.live.proxy.LivePublicProxy
import com.polaris.live.ui.live.proxy.caller.CallVideoListenerProxy
import com.polaris.live.ui.live.proxy.gift.CallGiftAnimationProxy
import com.polaris.live.ui.live.widget.listener.OnBackPressedListener
import com.polaris.live.ui.live.widget.listener.OnCallEventListener
import com.polaris.live.ui.live.widget.listener.OnChangeCameraListener
import com.polaris.live.ui.live.widget.listener.OnLiveCallCallback
import com.polaris.live.ui.live.widget.listener.OnTranslationChangeListener
import com.polaris.live.ui.message.fragment.MessageSessionFragment
import com.polaris.live.ui.message.fragment.dialog.MessageSingleDialogFragment
import com.polaris.live.utils.CommonUtils
import com.polaris.live.utils.LiveUtils
import com.polaris.live.utils.XPopupUtils
import com.polaris.live.utils.fragment.FragmentUtils
import com.polaris.live.utils.fragment.showNewDialogFragment
import com.polaris.live.utils.image.ImageUtils
import com.polaris.live.utils.image.normal
import com.polaris.live.utils.zego.LiveEngineManage
import com.polaris.live.viewmodel.live.CallVideoViewModel
import im.zego.zegoexpress.callback.IZegoEventHandler
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.nio.charset.StandardCharsets

/**
 * CallLiveVideoFragment        拨打方和接听方的fragment
 *
 * @author Created by 半仙 on 2023/9/12/012 17:10
 */
class CallVideoFragment : GestureFragment<CallVideoViewModel, FragmentCallLiveVideoBinding>(),
    OnBackPressedListener,
    OnCallEventListener,
    OnChangeCameraListener {

    //通话的基本信息
    private val mCallInfo by lazy {
        arguments?.getParcelable<CallVo>(LiveConst.Params.CALL_INFO)
            ?: throw IllegalArgumentException("callModel is null")
    }

    private var mCallBean: CallStartResp? = null //接收方的信息
    private var mCallMessage: CallSignalingMessage? = null //拨打方的信息
    private var mOtherUserBasic: UserBasicVo? = null //对方的的基本信息
    private var lastIndex = 3

    private val mGiftAdapter by lazy { CallGiftAdapter() }
    private val mLiveMoreProxy by lazy {
        LiveMoreProxy(
            requireContext(), this, mViewModel,
            pageType,
            this,
            null
        )
    }

    private val mCallVideoListenerProxy by lazy {
        CallVideoListenerProxy(
            requireContext(),
            mBinding
        )
    }
    private val mLivePublicProxy by lazy {
        LivePublicProxy(requireContext(), mViewModel)
    }

    //礼物动画代理
    private var mGiftAnimProxy: CallGiftAnimationProxy? = null

    //礼物列表消息  延迟后添加快捷礼物列表
    private var mGiftJob: Job? = null

    private val mGiftDialog by lazy {
        GiftDialogFragment(
            AppConst.GiftComming.CALL,
            AppConst.BackpackGiftComming.CALL,
            null,
            true
        ) { giftSendBean ->
            val sendGiftBean = SendGiftBean(
                getOtherUserId(),
                giftSendBean.gift.id,
                giftSendBean.num,
                AppConst.GiftComming.CALL,
                mCallInfo.id,
                giftSendBean.backpackId,
                payload = giftSendBean.gift.payload
            )
            mViewModel.sendGift(
                requireContext(),
                sendGiftBean,
                LiveConst.SendGift.giftPopup,
                giftSendBean.gift.pic,
                false
            )
        }.also {
            ifDestroy {
                if (it.fragmentManager != null) {
                    //因为当LifecycleOwner回调ON_DESTROY的时候fragment的状态已经保存了，此时再调用FragmentManager相关的东西就会报IllegalStateException
                    if (isAdded && !isStateSaved) {
                        it.dismiss()
                    } else {
                        it.dismissAllowingStateLoss()
                    }
                }
            }
        }
    }
    private var isFree = false

    private var isInitTranslation = false

    private var mPlayFirstFrame: Boolean = false

    private var mOnLiveCallCallback: OnLiveCallCallback? = null

    //同声传译设置后回调
    private var mOnTranslateChange: OnTranslationChangeListener? = null

    private val mEventHandler = object : IZegoEventHandler() {
        override fun onPlayerSyncRecvSEI(streamID: String?, data: ByteArray) {
            super.onPlayerSyncRecvSEI(streamID, data)
            mViewModel.viewModelScope.launch {
                try {
                    val str = String(data, StandardCharsets.UTF_8).substring(LiveConst.ZEGONUM)
                    if (!TextUtils.isEmpty(str)) {
                        mBinding.vTransition.onTranslationText(
                            getOtherUser(),
                            GsonUtils.fromJson(str, RecognizeModel::class.java)
                        )
                    }
                    GsonUtils.getGson().toJsonTree("")

                } catch (_: Exception) {
                }
            }
        }
    }

    private val mOnAppStatusChangedListener = object : Utils.OnAppStatusChangedListener {
        override fun onForeground(activity: Activity?) {
            mViewModel.stopKillActivityTimeout()
            mViewModel.isForeground = true
        }

        override fun onBackground(activity: Activity?) {
            mViewModel.isForeground = false
            mViewModel.killActivityTimeout(maxBackgroundTime)
        }
    }

    private fun initImmersionBar() {
        ImmersionBar.with(this)
            .transparentBar()
            .titleBarMarginTop(mBinding.rlContent)
            .init()

        NavigationBarUtils.setNavigationHeight(mBinding.rlContent)
    }

    override fun initView(savedInstanceState: Bundle?) {
        super.initView(savedInstanceState)
        initImmersionBar()
        EventBus.getDefault().register(this)
        LiveEngineManage.eventHandlerHelper.addEventHandler(mEventHandler)

        //理论上数据不可能为空，为空不往下走
        mCallBean = arguments?.getParcelable(LiveConst.Params.CALL_BEAN)
        mCallMessage = arguments?.getParcelable(LiveConst.Params.CALL_MESSAGE)
        mOtherUserBasic = arguments?.getParcelable(LiveConst.Params.CALL_USER_BASIC)

        mGiftAnimProxy = CallGiftAnimationProxy(
            requireContext(),
            mBinding.llGift,
            viewLifecycleOwner,
            mViewModel
        )

        mBinding.apply {
            val otherSex: Int?

            //接收方取message
            if (isAnswer()) {
                val callMessage = mCallMessage
                otherSex = if (callMessage != null) {
                    vHeader.initData(pageType, mCallInfo, callMessage)

                    callMessage.sex
                } else {
                    val userBasic = mOtherUserBasic
                    if (userBasic != null) {
                        vHeader.initData(pageType, mCallInfo, userBasic)
                    }

                    userBasic?.sex
                }
            } else {//播打方取bean
                val userBasic = mCallBean?.answer ?: mOtherUserBasic
                if (userBasic != null) {
                    vHeader.initData(pageType, mCallInfo, userBasic)
                }

                otherSex = userBasic?.sex
            }

            if (isPayer()) {
                answerTitleLl.visibility = View.GONE
            } else {
                answerTimeText.visibility = View.GONE
                val safeLevel = UserManager.getUser().flag?.safeLevel
                val safeType = UserManager.getUser().flag?.safeType


                if (mCallMessage?.earnings != 0L) {
                    val isHideClose =
                        !CommonUtils.isMan(UserManager.getUser().sex) &&
                                CommonUtils.isSafeUser(safeLevel, safeType)

                    if (isHideClose) {
                        closeVideo.visibility = View.INVISIBLE

                        mViewModel.viewModelScope.launch {
                            //需求延迟20后显示挂断按钮
                            delay(LiveConst.LIVE_SHOW_CLOSE_DELAY)
                            withContext(CoroutineScopeManager.mainDispatcher) {
                                closeVideo.visibility = View.VISIBLE
                            }
                        }
                    }
                }

            }

            Glide.with(requireContext())
                .load(ImageUtils.imgPath(mCallBean?.cover))
                .normal()
                .into(userCover)
            vMessage.initData(pageType, mCallInfo)
            vEdit.initData(mCallInfo)
            vTransition.initData(
                otherSex,
                mCallBean?.answer?.avatar,
                mCallBean?.answer?.avatarFrame,
                isPayer()
            )
            tvCalling.initView(viewLifecycleOwner)
            giftRecycler.apply {
                layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
                addItemDecoration(CommonItemDecoration(leftMargin = ConvertUtils.dp2px(8f)))
                adapter = mGiftAdapter
            }

            if (isStarted()) {
                handleStartView()
            }

            isFree = mCallMessage?.earnings == 0L

            if (mCallBean?.call?.simulInterpret == true) {
                ivTranslate.setImageResource(R.drawable.ic_translate)
                vTransition.setVisible(View.VISIBLE)
            } else {
                ivTranslate.setImageResource(R.drawable.ic_translate_off)
                vTransition.setVisible(View.GONE)
            }
            //如果语言相同隐藏同声传译
            if (mCallBean?.call?.sameLanguage == true) {
                ivTranslate.visibility = View.GONE
                mOnTranslateChange?.onTranslationSwitch(false)
            } else {
                mOnTranslateChange?.onTranslationSwitch(true)
                ivTranslate.visibility = View.VISIBLE
            }
        }
        mViewModel.launchRecharge()
        initView()
        initListener()
        initObserve()
    }

    private fun initView() {
        mGiftAdapter.setOnItemClickListener { _, _, position ->
            DebounceHelper.singleClick {
                val type = if (mGiftAdapter.data[position].type == LiveConst.GiftType.FOLLOWER_GIFT) {
                    LiveConst.SendGift.followerGift
                } else {
                    LiveConst.SendGift.giftPopup
                }
                val gift = mGiftAdapter.data[position]
                mViewModel.sendGift(
                    requireContext(),
                    SendGiftBean(
                        recipient = getOtherUserId(),
                        giftId = gift.id,
                        count = 1,
                        sourceType = AppConst.GiftComming.CALL,
                        objectId = mCallInfo.id,
                        payload = gift.payload
                    ), type,
                    null,
                    false
                )
                if (mGiftAdapter.data[position].type == LiveConst.GiftType.FREE_GIFT) {
                    mGiftAdapter.removeAt(position)
                }
            }
        }
        val type = if (CommonUtils.isMan(UserManager.getUser().sex)) {
            AppConst.GiftComming.CALL_MAN_SHORTCUT
        } else {
            AppConst.GiftComming.CALL_WOMAN_SHORTCUT
        }
        mGiftAdapter.setList(CommonCache.getGiftBean(type))
    }

    private fun initObserve() {
        AppUtils.registerAppStatusChangedListener(mOnAppStatusChangedListener)

        /**
         * 周星数据更新
         */
        mViewModel.weeklyStarRankData.observe(this) { state ->
            parseState(state, {
                if (it.show) {
                    mViewModel.cancelPollingWeeklyStarRank()
                    mBinding.weekStar.visibility = View.VISIBLE
                    it.base?.let { da ->
                        mBinding.weekStar.setData(da)
                    }
                } else {
                    mViewModel.pollingWeeklyStarRank()
                    mBinding.weekStar.visibility = View.GONE
                }
            }, {
                //报错开启定时请求
                mViewModel.pollingWeeklyStarRank()
            })
        }
        //发送礼物后如果position不为空那么代表就是送的邀请关注礼物
        mViewModel.sendFollowerLiveData.observe(this) {
            when (it) {
                LiveConst.SendGift.followerGift -> clearFollower()
            }
        }
        //发送礼物后得到返回的数量数据
        mViewModel.sendGiftLiveData.observe(this) {
            it.backpackId?.let { id ->
                val amount =
                    (it.ext?.get("backpackAccount") as? Map<*, *>)?.get("amount")?.toString()
                        ?.toDoubleOrNull()?.toLong()
                if (amount != null) {
                    mGiftDialog.upBackpackIdAllCount(id, amount)
                }
            }
        }
        mViewModel.callConnectLiveData.observe(this) { state ->
            parseState(state, {
                startCallSuccessful(it.getTime)
                if (isPayer()) {
                    mViewModel.getCallPromotion()
                }
                if (it.ivParameter != null) {
                    initTranslation(it.ivParameter, it.translationLanguage)
                }
            }, {
                //失败直接通知结束
                stopCallFailure()
            })
        }
        //关注主播
        mViewModel.followerLiveData.observe(this) { resultState ->
            parseState(resultState, {
                ToastGravity.showGravity(string.follower_succeed)
                clearFollower()
            }, {
                ToastGravity.showGravity(it.errorMsg)
            })
        }
        //心跳检测
        mViewModel.callHeartbeatLiveData.observe(this) { resultState ->
            parseState(resultState, {
                mCallVideoListenerProxy.onCheckCallBackChange(it)
            })
        }
        mViewModel.callHeartbeatFailureLiveData.observe(this) {
            if (it) {
                //失败需要断开
                stopCallFailure()

                //如果是出现异常则调用通话结束
                mViewModel.callEnd(mCallInfo.id, LiveConst.CloseType.ERROR, UserManager.getUserId())
            }
        }
        //通话计时
        mViewModel.callCountdownLiveData.observe(this) {
            if (isPayer()) {
                mBinding.answerTimeText.text =
                    LiveUtils.formatTime(it).convertArabicDigitsToNormal()
            } else {
                mBinding.vHeader.updateTime(it)
            }
        }
        //关闭通话
        mViewModel.callEndLiveData.observe(this) { state ->
            parseState(state, {
                stopCallSuccessful(it)
            }, {
                stopCallSuccessful(null)
            })
        }
        //等待接听超时
        mViewModel.answerTimeoutLiveData.observe(this) {
            if (isAnswer()) {
                //如果是应答方需要主动结束
                mViewModel.callEnd(
                    mCallInfo.id,
                    LiveConst.CloseType.TIMEOUT,
                    UserManager.getUserId()
                )
            } else {
                stopCallSuccessful(null)
            }
        }
        //通话公屏消息
        ImCallManager.observePublicMessage(this, { mCallInfo.id }, { message ->
            if (message.type in ImCallManager.publicTypes && message.businessId == mCallInfo.id) {
                mBinding.vMessage.getMessageView().addMessage(message)
            }

            //其他消息处理
            when (message.type) {
                //拉起充值页面
                LIVE_RECHARGE_PAY -> {
                    val payload = message.payload as CallLaunchRechargePayloadBean
                    GlobalPopupManager.showRechargePopup(
                        requireContext(),
                        mViewModel,
                        message.content,
                        payload.duration,
                        isNeedBottom = true
                    )
                }
                //礼物动画
                LIVE_SEND_GIFT -> {
                    val payload = message.payload as InviteGiftPayloadBean
                    if (payload.gift.animation != null) {
                        mBinding.widgetGift.setGift(payload)
                    } else {
                        mGiftAnimProxy?.addGift(message)
                    }
                }
                //礼物提示消息
                LIVE_GIFT_LIST -> {
                    val payload = message.payload as GiftListPayloadBean
                    val orNull = payload.gifts.getOrNull(0)

                    orNull?.let {
                        mBinding.widgetSendGift.setData(
                            payload,
                            mOtherUserBasic?.avatar,
                            mOtherUserBasic?.userId
                        )
                        playAnim(listOf(inAlpha(mBinding.widgetSendGift)))
                        mGiftJob = lifecycleScope.launch(CoroutineScopeManager.ioDispatcher) {
                            delay(payload.duration * 1000)
                            withContext(CoroutineScopeManager.mainDispatcher) {
                                if (mBinding.widgetSendGift.isVisible) {
                                    playAnim(listOf(outAlpha(mBinding.widgetSendGift)))
                                    mGiftAdapter.addData(0, payload.gifts)
                                    mGiftAdapter.notifyDataSetChanged()
                                }
                            }
                        }
                    }

                }
                //遮挡消息
                LIVE_OCCLUSION_MESSAGE -> {
                    val payload = message.payload as CallObstructPayloadBean
                    if (payload.obstruct) {
                        if (!mBinding.llObstruct.isVisible) {
                            playAnim(listOf(inAlpha(mBinding.llObstruct)))
                        }
                    } else {
                        if (mBinding.llObstruct.isVisible) {
                            playAnim(listOf(outAlpha(mBinding.llObstruct)))
                        }
                    }
                }
                //遮罩消息
                LIVE_MASKING_MESSAGE -> {
                    mBinding.maskView.maskState(message)
                }
                //警告消息
                LIVE_WARN_MESSAGE -> {
                    mLivePublicProxy.onPublicMessage(message)
                }
                //同声传译开关
                LIVE_TRANSLATION_MESSAGE -> {
                    val payload = message.payload as SimultaneousStartPayloadBean
                    if (payload.open) {

                        isFree = false

                        if (!isInitTranslation && !payload.ivParameter.isNullOrEmpty() && !payload.translationLanguage.isNullOrEmpty()) {
                            initTranslation(payload.ivParameter, payload.translationLanguage)
                        }

                        mCallBean?.call?.simulInterpret = true
                        mBinding.ivTranslate.visibility = View.VISIBLE
                        mBinding.ivTranslate.setImageResource(R.drawable.ic_translate)
                        mBinding.vTransition.setVisible(View.VISIBLE)
                    } else {
                        mCallBean?.call?.simulInterpret = false
                        mBinding.ivTranslate.visibility = View.GONE
                        mBinding.ivTranslate.setImageResource(R.drawable.ic_translate_off)
                        mBinding.vTransition.setVisible(View.GONE)
                    }
                    mOnTranslateChange?.onTranslationSwitch(payload.open)
                }

                CALL_REFUSE_INTERPRETATION -> { //拒绝同声传译
                    PublicTipsPopup.show(
                        requireContext(), this,
                        StringUtils.getString(string.prompt),
                        message.content,
                        StringUtils.getString(string.continue_connecting),
                        StringUtils.getString(string.end_connection),
                    ) {
                        val type = if (isStarted()) {
                            LiveConst.CloseType.CANCEL
                        } else {
                            LiveConst.CloseType.END
                        }
                        mViewModel.callEnd(mCallInfo.id, type, UserManager.getUserId(), true)
                    }
                }

                REQUEST_GIFT_POPUP_MESSAGE -> { //索要礼物弹出消息
                    val payload = message.payload as InviteGiftPopupPayloadDto
                    RequestGiftPopup.show(
                        requireContext(), this,
                        payload,
                        {
                            mViewModel.inviteGift(mCallInfo.id)
                        }
                    )
                }
            }
        })
        ImCallManager.observe(this, { mCallInfo.id }) {
            //已打通
            withMessage<CallSignalingMessage>(COMMAND_CALL_END) {
                stopCallSuccessful(it.getCallVo() ?: mCallInfo)
            }
            //对方已接通
            withMessage<CallSignalingMessage>(COMMAND_CALL_ANSWER) {
                if (isStarted()) {
                    onAnswerSuccess(it)
                }
            }
            //未打通
            withMessage<CallSignalingMessage>(COMMAND_CALL_NO_ANSWER) {
                if (isStarted()) {
                    stopCallSuccessful(null)

                    ToastGravity.showGravity(string.call_no_answer)
                }
            }
            withMessage<CallSignalingMessage>(COMMAND_CALL_REFUSE) {
                if (isStarted()) {
                    stopCallSuccessful(null)
                    lifecycleScope.launch(CoroutineScopeManager.mainDispatcher) {
                        ToastGravity.showGravity(string.call_request_denied)
                    }
                }
            }
        }
        //通话页面的浮窗价格
        mViewModel.callPayLiveData.observe(this) { resultState ->
            parseState(resultState, {
                if (!isAnswer()) {
                    mBinding.callPay.setData(it, viewLifecycleOwner, mViewModel)
                }
            })
        }
        //如果首冲弹出了刷新快捷充值列表
        mViewModel.isShowRechargeLiveData.observe(this) {
            mViewModel.getCallPromotion()
        }
    }

    private fun initListener() {
        mBinding.apply {
            /**
             * 展示详情弹窗
             */
            weekStar.setShowDetail {
                WeeklyStarPopup.showPop(requireContext(), this@CallVideoFragment, mViewModel, lastIndex) {
                    lastIndex = it
                }
            }
            /**
             * 周星是否显示数据
             */
            weekStar.setShowWeekStarCallBack {
                if (it) {
                    mViewModel.pollingWeeklyStarRank()
                } else {
                    mViewModel.cancelPollingWeeklyStarRank()
                }
            }

            //点击关注
            vHeader.setOnFollowerClickListener {
                mViewModel.addFollower(getOtherUserId())
            }
            //点击主播头像
            vHeader.setOnAvatarClientListener {
                //等待接听的状态无需展示
                if (isStarted()) return@setOnAvatarClientListener
                showUserProfile()
            }
            //显示头像
            vMessage.getMessageView().setOnUserProfileClickListener {
                showUserProfile()
            }
            //显示输入框
            ivSend.setOnSingleClickListener {
                vEdit.showKeyboard()
            }
            //显示礼物
            ivGift.setOnSingleClickListener {
                getOtherUser()?.also {
                    showGiftDialog(it.avatar, it.avatarFrame)
                }
            }
            //发送公屏消息
            vEdit.setOnSendPublicMessageListener {
                mViewModel.sendPublicMessage(it)
            }
            //点击更多
            callMore.setOnSingleClickListener {
                val userId = getOtherUser()?.userId
                val nickname = getOtherUser()?.nickname
                val objectId = mCallInfo.id
                if (userId != null && nickname != null) {
                    mLiveMoreProxy.showVideoMore(userId, nickname, objectId, {
                        mBinding.vEdit.setKeyboardListerState(it)
                    })
                }
            }
            //关闭视频
            closeVideo.setOnSingleClickListener {
                showStopPopup()
            }

            //点击隐藏edit
            ViewUtils.registerTouchDown(vShade) {
                vEdit.hideKeyboard()
            }
            //点击快捷充值
            callPay.onSetClickListener { payResp ->
                GooglePayManager.buyShow(
                    requireActivity(),
                    payResp.priceId,
                    UserConst.From.UNKNOWN,
                    payResp.payerRechargeRewardsType,
                    price = payResp.price,
                    onSuccess = {
                        mViewModel.getCallPromotion()
                    }, onFailure = {
                        mViewModel.getCallPromotion()
                    })
            }
            //赠送关注礼物
            vMessage.getMessageView().setOnSendFollowerListener {
                mViewModel.sendGift(
                    requireContext(),
                    it,
                    LiveConst.SendGift.followerGift,
                    null,
                    false
                )
            }
            //赠送礼物
            vMessage.getMessageView().setOnSendGiftListener {
                mViewModel.sendGift(
                    requireContext(),
                    it,
                    LiveConst.SendGift.publicGift,
                    null,
                    false
                )
            }
            //遮罩消息点击举报
            maskView.setOnMaskReportListener {
                //接收方取message
                val userId = if (isAnswer()) {
                    val callMessage = mCallMessage
                    callMessage?.sender ?: mOtherUserBasic?.userId
                } else {
                    val userBasic = mCallBean?.answer ?: mOtherUserBasic
                    userBasic?.userId
                }

                if (userId != null) {
                    mCallBean?.answer?.nickname?.let {
                        GlobalPopupManager.showReport(
                            requireContext(), it, mViewModel,
                            userId, mCallBean?.call?.id,
                            owner = this@CallVideoFragment
                        )
                    }
                }

            }
            //点击同声传译区域
            vTransition.setOnSingleClickListener {
                ivTranslate.performClick()
            }
            //同声传译
            ivTranslate.setOnSingleClickListener {
                val isShow = isAnswer()
                XPopupUtils.showPopup(
                    SetTranslationPopup(
                        requireActivity(),
                        isShow,
                        mCallBean?.call?.simulInterpret,
                        mViewModel, {
                            mOnTranslateChange?.onSetSpeechLanguage(it)
                        }, {
                            mCallBean?.call?.simulInterpret = it
                            if (it) {
                                isFree = false
                                vTransition.setVisible(View.VISIBLE)
                                mBinding.ivTranslate.setImageResource(R.drawable.ic_translate)
                            } else {
                                vTransition.setVisible(View.GONE)
                                mBinding.ivTranslate.setImageResource(R.drawable.ic_translate_off)
                            }
                            mCallBean?.call?.id?.let { it1 ->
                                mOnTranslateChange?.onTranslationSwitch(it)
                                mViewModel.openSwimultaneous(it1, it)
                            }
                        }),
                    lifecycle = lifecycle
                )
            }
            //点击屏幕中间的礼物
            widgetSendGift.setOnCallSendGiftList { gift, type ->
                mViewModel.sendGift(
                    requireContext(),
                    SendGiftBean(
                        recipient = getOtherUserId(),
                        giftId = gift.id,
                        count = 1,
                        sourceType = AppConst.GiftComming.CALL,
                        objectId = mCallInfo.id,
                        payload = gift.payload
                    ), LiveConst.SendGift.followerGift,
                    null,
                    false
                )
                if (widgetSendGift.isVisible) {
                    mGiftJob?.cancel()
                    playAnim(listOf(outAlpha(widgetSendGift)))
                }
            }
            //快捷充值倒计时结束
            callPay.setOnTimeFinishListener {
                mViewModel.getCallPromotion()
            }
        }
    }

    override fun initData() {
        //只有等待接通才需要开启超时接听
        if (isStarted()) {
            mViewModel.launchAnswerTimeout()
        }

        /**
         * 接听方获取周星数据
         */
        if (isAnswer() && mCallMessage?.earnings == 0L) {
            mViewModel.getWeeklyStarRank()
        }
    }

    private fun showGiftDialog(avatar: String, avatarFrame: String?) {
        val fragmentManager = FragmentUtils.getFragmentManager(requireContext())
            ?: return

        mGiftDialog.apply {
            setUserId(getOtherUserId(), getOtherUser()?.nickname)
            show(fragmentManager, GiftDialogFragment.FRAGMENT_TAG)
        }
    }

    //未接通
    private fun handleStartView() {
        mBinding.apply {
            tvCalling.showWaiting()

            answerTimeText.visibility = View.GONE
            callMore.visibility = View.GONE
            llBottom.visibility = View.GONE
            giftRecycler.visibility = View.GONE
        }
    }

    //已接通
    private fun handleConnectView() {
        if (isPayer()) {
            mBinding.answerTimeText.visibility = View.VISIBLE
        }

        mBinding.callMore.visibility = View.VISIBLE
        mBinding.llBottom.visibility = View.VISIBLE
        mBinding.giftRecycler.visibility = View.VISIBLE

        mBinding.tvCalling.hideWaiting()
    }

    override fun onPlayFirstFrame() {
        withLoaded {
            if (!isConnected()) {
                connected()
            }
            mPlayFirstFrame = true
            mBinding.userCover.visibility = View.GONE
        }
    }

    override fun onTranslating(model: RecognizeModel) {
        mBinding.vTransition.onTranslationText(getOtherUser(), model)
    }

    override fun onTranslated(model: RecognizeModel) {
        mBinding.vTransition.onTranslationText(getOtherUser(), model)
    }

    override fun onAnswerSuccess(callBean: CallStartResp, callMessage: CallSignalingMessage) {
        withLoaded {
            mCallBean = callBean

            onAnswerSuccess(callMessage)
        }
    }

    private fun onAnswerSuccess(callMessage: CallSignalingMessage) {
        mCallMessage = callMessage
        if (!isConnected() && mPlayFirstFrame) {
            connected()
        }
    }

    private fun connected() {
        //拿到对方的帧可以开始通话了
        mViewModel.callConnect(mCallInfo.id)

        mCallInfo.status = LiveConst.CallState.ANSWER
    }

    private fun startCallSuccessful(getTime: Long) {
        mCallInfo.status = LiveConst.CallState.CONNECTED
        mCallInfo.getTime = getTime

        handleConnectView()

        //通话终于建立了
        mCallBean.apply {
            mViewModel.launchCallHeartbeat(mCallInfo.id, getTime)
            mViewModel.launchCallCountdown(getTime)

            LiveUtils.resolveScreenshotStrategy(LiveConst.Page.CALL, mCallInfo.screenshotStrategy)
                ?.also {
                    mViewModel.launchScreenshot(pageType, mCallInfo.id, getTime, it)
                }
        }
    }

    //最终错误的结束通话
    private fun stopCallFailure() {
        stopCallSuccessful(null)
    }

    //最终成功的结束通话
    private fun stopCallSuccessful(callInfo: CallVo?) {
        if (isEnded()) {
            return
        }
        mOnLiveCallCallback?.onCallStop(callInfo, mCallBean, mCallMessage, mViewModel.isForeground)

        mViewModel.resetLiveJob()

        mCallInfo.status = LiveConst.CallState.OVER
    }

    //移除所有关注礼物
    private fun clearFollower() {
        val list = mutableListOf<GiftBean>()
        mGiftAdapter.data.forEach {
            if (it.type != LiveConst.GiftType.FOLLOWER_GIFT) {
                list.add(it)
            }
        }
        mGiftAdapter.setList(list)
        mBinding.vMessage.getMessageView().clearFollower()
        mBinding.vHeader.updateFollowStatus(true)
    }

    private fun showStopPopup() {
        XPopupUtils.showViewPopup(
            CallHangUpDialog(
                requireContext(),
                mCallInfo.getTime ?: CacheUtil.getServerTime(),
                isPayer(),
                isFree,
                false
            ) {
                val type = if (isStarted()) {
                    LiveConst.CloseType.CANCEL
                } else {
                    LiveConst.CloseType.END
                }
                mViewModel.callEnd(mCallInfo.id, type, UserManager.getUserId(), true)
            },
            lifecycle = lifecycle
        )
    }

    override fun onStop() {
        super.onStop()
        if (LiveStateManager.isRecharging()) {
            EventBus.getDefault().postSticky(LiveRechargeEvent(GlobalPopupManager.isShowRecharge()))
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        LiveEngineManage.eventHandlerHelper.removeEventHandler(mEventHandler)
    }

    override fun onBackPressed(): Boolean {
        if (!isCreated() || activity?.isFinishing != false) {
            return true
        }

        showStopPopup()

        return true
    }

    override fun onChangeCamera() {
        mOnLiveCallCallback?.onChangeCamera()
    }

    /**
     * 展示消息列表
     */
    private fun showChatMessage(userBase: UserBasicVo) {
        childFragmentManager.showNewDialogFragment(
            MessageSingleDialogFragment(
                userBase.userId,
                userBase.avatar,
                userBase.avatarFrame,
                userBase.chatBubble,
                nestedPage = false,
                singlePage = true,
                false
            ),
            MessageSessionFragment.FRAGMENT_TAG,
            this
        )
    }

    private var _otherMessageUser: UserBasicVo? = null

    //获取对方的基本信息
    private fun getOtherUser(): UserBasicVo? {
        return _otherMessageUser ?: let {
            LiveUtils.getCallOtherUser(mCallBean, mCallMessage, mOtherUserBasic).apply {
                mOtherUserBasic = this
            }
        }
    }

    private fun getOtherUserId() = if (mCallInfo.senderId != UserManager.getUserId()) {
        mCallInfo.senderId
    } else {
        mCallInfo.answerId
    }

    //是接收方
    private fun isAnswer(): Boolean {
        return mCallInfo.answerId == UserManager.getUserId()
    }

    //是付费方
    private fun isPayer(): Boolean {
        return mCallInfo.payUserId == UserManager.getUserId()
    }

    //拨打中
    private fun isStarted(): Boolean {
        return mCallInfo.status == LiveConst.CallState.START
    }

    //双方已同意
    private fun isReady(): Boolean {
        return mCallInfo.status > LiveConst.CallState.START && mCallInfo.status < LiveConst.CallState.CONNECTED
    }

    //通话是否准备好了
    private fun isConnected(): Boolean {
        return mCallInfo.status == LiveConst.CallState.CONNECTED
    }

    //通话是否已经结束
    private fun isEnded(): Boolean {
        return mCallInfo.status == LiveConst.CallState.OVER
    }

    //初始化同声传译
    private fun initTranslation(iv: String, translationLanguage: String?) {
        if (isInitTranslation) return
        val key = mCallInfo.simultaneousEncrypt?.let { EncryptHelper.decryptParams(it, iv) }
        val speechLanguage = UserManager.getUser().profile?.spokenLanguage
        if (key != null && translationLanguage != null && speechLanguage != null) {
            mOnTranslateChange?.onInitTranslation(key, translationLanguage, speechLanguage)
            isInitTranslation = true
        }
    }

    //展示更多卡片
    private fun showSelectCard(infoOtherResp: InfoOtherResp) {
        context?.let {
            GlobalPopupManager.showLiveSelectMoreCard(
                it, this, mViewModel,
                infoOtherResp, mCallInfo.id, mCallInfo.userId,
                onAtClickListener = {
                    mBinding.vEdit.atUser(infoOtherResp.userId, infoOtherResp.nickname)
                }
            )
        }
    }

    //展示用户资料卡片
    private fun showUserProfile() {
        showUserProfilePopup(
            requireContext(), this, mViewModel,
            getOtherUserId(), UserConst.From.LIVE, objectId = mCallInfo.id,
            onMessageClickListener = { info ->
                if (isCreated() && !isDestroyView()) {
                    showChatMessage(info.toUserBasicVo())
                }
            },
            onFollowerClickListener = {
                clearFollower()
            },
            onSelectMoreCardListener = {
                showSelectCard(it)
            },
            onGiftClickListener = {
                showGiftDialog(it.avatar, it.decoration?.avatarFrame)
            }
        )
    }

    override fun setOnLiveCallCallback(l: OnLiveCallCallback) {
        this.mOnLiveCallCallback = l
    }

    override fun onShowView() {
        val width = ScreenUtils.getScreenWidth()
        playAnim(
            listOf(
                inLeft(mBinding.vMessage, width),
                inLeft(mBinding.vHeader, width),
                inLeft(mBinding.llTop, width),
                inLeft(mBinding.giftRecycler, width),
                inLeft(mBinding.callPay, width),
                inLeft(mBinding.vTransition, width),
                inLeft(mBinding.callMore, width),
            )
        )
        ViewUtils.cleanViewVisible(mBinding.ivTranslate)
    }

    override fun onHideView() {
        val width = ScreenUtils.getScreenWidth()
        playAnim(
            listOf(
                outRight(mBinding.vMessage, width),
                outRight(mBinding.vHeader, width, View.INVISIBLE),
                outRight(mBinding.llTop, width),
                outRight(mBinding.giftRecycler, width),
                outRight(mBinding.callPay, width),
                outRight(mBinding.vTransition, width),
                outRight(mBinding.callMore, width),
            )
        )
        ViewUtils.cleanViewVisible(mBinding.ivTranslate)
    }

    fun setOnTranslateChangeListener(l: OnTranslationChangeListener) {
        mOnTranslateChange = l
    }

    override fun isGesture(): Boolean {
        return !mBinding.pdView.isDisallowInterceptTouchEvent()
    }

    override fun onDestroy() {
        super.onDestroy()
        EventBus.getDefault().unregister(this)
        AppUtils.unregisterAppStatusChangedListener(mOnAppStatusChangedListener)
        isInitTranslation = false
        mOnTranslateChange?.onTranslationSwitch(isOpen = false, needUnInit = true)
        mOnLiveCallCallback = null

        if (isCreated()) {
            mViewModel.stopKillActivityTimeout()
        }
    }

    /**
     * 在后台计时到
     */
    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onBackGroundEvent(event: BackgroundEvent) {
        if (isAnswer()) {
            mViewModel.callEnd(
                mCallInfo.id,
                LiveConst.CloseType.ERROR,
                UserManager.getUserId()
            )
        }
    }

    companion object {

        private const val pageType = LiveConst.Page.CALL

        private const val maxBackgroundTime = 20000L //接听方在后台停留挂断事件
    }
}
